package com.dingwen.treasure.log.service.impl;

import cn.hutool.json.JSONUtil;
import com.dingwen.treasure.base.constant.RabbitmqConstant;
import com.dingwen.treasure.base.pojo.vo.Result;
import com.dingwen.treasure.log.entity.SystemOperateLog;
import com.dingwen.treasure.log.feign.TreasureManageFeignClient;
import com.dingwen.treasure.log.service.LogService;
import com.dingwen.treasure.model.entity.mybatisplus.SysUser;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.http.HttpStatus;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * 　LogServiceImpl </br>
 * <pre>
 *      1. @Async() 不指定线程池时使用的时使用默认的，需要指定自定义的线程池需要指定线程池的BeanId。注意需要使用@Async功能必须通过@EnableAsync开启
 *  </pre>
 * 　@author dingwen
 * 　@date 2022/6/26
 */
@Service
@Slf4j
@RabbitListener(queues = {RabbitmqConstant.QUEUE_OPERATOR_LOG}, concurrency = "10", ackMode = "MANUAL")
public class LogServiceImpl implements LogService {

    /**
     * systemOperateLogService
     */
    @Resource
    private  SystemOperateLogService systemOperateLogService;


    /**
     * treasureManageFeignClient
     */
    @Resource
    private  TreasureManageFeignClient treasureManageFeignClient;

    /**
     * 保存系统操作员日志
     *
     * @param messages 信息
     * @param message  消息
     * @param channel  频道
     */
    @Async(value = "asyncExecutor")
    @SneakyThrows(Throwable.class)
    @RabbitHandler
    @Override
    public void saveSystemOperatorLog(Message messages, String message, Channel channel) {
        // 消息Id
        long deliveryTag = messages.getMessageProperties().getDeliveryTag();
        if (!JSONUtil.isJson(message)) {
            log.error("{}消息消费，消息内容，不是JSON", RabbitmqConstant.QUEUE_OPERATOR_LOG);
            // 启用delivery tag,不进入死信信队列
            //TODO nack 知识点残缺补漏
            channel.basicNack(deliveryTag, Boolean.FALSE, Boolean.FALSE);
            return;
        }

        SystemOperateLog systemOperateLog = JSONUtil.toBean(message, SystemOperateLog.class);

        // feign 调用 manage 获取用户详细信息
        Object Object = queryUserInfo(Long.valueOf(systemOperateLog.getOperatorId()));

        systemOperateLog.setUserInfo(JSONUtil.toJsonStr(Object));

        // 存储到 mongo
        systemOperateLogService.sava(systemOperateLog);

        // 单条消息消费确认， multiple： false (reject just the supplied delivery tag)
        channel.basicAck(deliveryTag, Boolean.FALSE);
    }

    /**
     * feign 调用 manage 查询用户信息
     *
     * @param userId 用户id
     * @return {@link SysUser}
     */
    @Override
    public Object queryUserInfo(Long userId) {
        Result<?> result = treasureManageFeignClient.getOneByUserId(userId);
        if (result.getCode() != HttpStatus.OK.value()) {
            return null;
        }
        return result.getData();
    }
}
